package repository

import (
	"context"
	"encoding/json"
	"time"
	"webook/feed/domain"
	"webook/feed/repository/cache"
	"webook/feed/repository/dao"
)

//var FolloweesNotFound = cache.FolloweesNotFound

type FeedEventRepo interface {
	// CreatePullEvents 创建拉事件
	CreatePullEvents(ctx context.Context, event domain.FeedEvent) error
	// CreatePushEvents 批量推送事件
	CreatePushEvents(ctx context.Context, events []domain.FeedEvent) error
	// FindPullEvents 获取拉事件，也就是关注的人发件箱里面的事件
	FindPullEvents(ctx context.Context, uids []int64, timestamp, limit int64) ([]domain.FeedEvent, error)
	// FindPushEvents 获取推事件，也就是自己收件箱里面的事件
	FindPushEvents(ctx context.Context, uid, timestamp, limit int64) ([]domain.FeedEvent, error)
	// FindPullEventWithTyp 获取某个类型的拉事件
	FindPullEventWithTyp(ctx context.Context, typ string, uids []int64, timestamp, limit int64) ([]domain.FeedEvent, error)
	// FindPushEventWithTyp 获取某个类型的推事件
	FindPushEventWithTyp(ctx context.Context, typ string, uid, timestamp, limit int64) ([]domain.FeedEvent, error)
}

type feedEventRepo struct {
	pullDAO   dao.FeedPullEventDAO
	pushDAO   dao.FeedPushEventDAO
	feedCache cache.FeedEventCache
}

func NewFeedEventRepo(pullDAO dao.FeedPullEventDAO,
	pushDAO dao.FeedPushEventDAO, feedCache cache.FeedEventCache) FeedEventRepo {
	return &feedEventRepo{
		pullDAO:   pullDAO,
		pushDAO:   pushDAO,
		feedCache: feedCache,
	}
}

func (f *feedEventRepo) CreatePushEvents(ctx context.Context, events []domain.FeedEvent) error {
	pushEvents := make([]dao.FeedPushEvent, len(events))
	for i, v := range events {
		pushEvents[i] = convertToPushEventDAO(v)
	}
	return f.pushDAO.CreatePushEvents(ctx, pushEvents)
}

func (f *feedEventRepo) CreatePullEvents(ctx context.Context, event domain.FeedEvent) error {
	return f.pullDAO.CreatePullEvent(ctx, convertToPullEventDAO(event))
}

func (f *feedEventRepo) FindPullEvents(ctx context.Context, uids []int64, timestamp, limit int64) ([]domain.FeedEvent, error) {
	list, err := f.pullDAO.FindPullEventList(ctx, uids, timestamp, limit)
	if err != nil {
		return nil, err
	}
	events := make([]domain.FeedEvent, len(list))
	for i, v := range list {
		events[i] = convertToPullEventDomain(v)
	}
	return events, nil
}

func (f *feedEventRepo) FindPushEvents(ctx context.Context, uid, timestamp, limit int64) ([]domain.FeedEvent, error) {
	events, err := f.pushDAO.GetPushEvents(ctx, uid, timestamp, limit)
	if err != nil {
		return nil, err
	}
	res := make([]domain.FeedEvent, len(events))
	for i, v := range events {
		res[i] = convertToPushEventDomain(v)
	}
	return res, nil
}

func (f *feedEventRepo) FindPullEventWithTyp(ctx context.Context, typ string, uids []int64,
	timestamp, limit int64) ([]domain.FeedEvent, error) {
	events, err := f.pullDAO.FindPullEventListWithType(ctx, typ, uids, timestamp, limit)
	if err != nil {
		return nil, err
	}
	ans := make([]domain.FeedEvent, len(events))
	for i, v := range events {
		ans[i] = convertToPullEventDomain(v)
	}
	return ans, nil
}

func (f *feedEventRepo) FindPushEventWithTyp(ctx context.Context, typ string, uid, timestamp, limit int64) ([]domain.FeedEvent, error) {
	events, err := f.pushDAO.GetPushEventsWithTyp(ctx, typ, uid, timestamp, limit)
	if err != nil {
		return nil, err
	}
	ans := make([]domain.FeedEvent, len(events))
	for i, v := range events {
		ans[i] = convertToPushEventDomain(v)
	}
	return ans, nil
}

func convertToPullEventDomain(event dao.FeedPullEvent) domain.FeedEvent {
	var ext map[string]string
	_ = json.Unmarshal([]byte(event.Content), &ext)
	return domain.FeedEvent{
		ID:    event.Id,
		Uid:   event.UID,
		Type:  event.Type,
		Ctime: time.Unix(event.Ctime, 0),
		Ext:   ext,
	}
}

func convertToPullEventDAO(event domain.FeedEvent) dao.FeedPullEvent {
	val, _ := json.Marshal(event.Ext)
	return dao.FeedPullEvent{
		Id:      event.ID,
		UID:     event.Uid,
		Type:    event.Type,
		Content: string(val),
		Ctime:   event.Ctime.Unix(),
	}
}

func convertToPushEventDomain(event dao.FeedPushEvent) domain.FeedEvent {
	var ext map[string]string
	_ = json.Unmarshal([]byte(event.Content), &ext)
	return domain.FeedEvent{
		ID:    event.Id,
		Uid:   event.UID,
		Type:  event.Type,
		Ctime: time.Unix(event.Ctime, 0),
		Ext:   ext,
	}
}

func convertToPushEventDAO(event domain.FeedEvent) dao.FeedPushEvent {
	val, _ := json.Marshal(event.Ext)
	return dao.FeedPushEvent{
		Id:      event.ID,
		UID:     event.Uid,
		Type:    event.Type,
		Content: string(val),
		Ctime:   event.Ctime.Unix(),
	}
}
